

<!DOCTYPE html>
<html lang="zh-CN">

<head><meta name="generator" content="Hexo 3.9.0">
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>你真的会用Fragment吗？Fragment常见问题以及androidx下Fragment的使用新姿势 - 杨云召 | 博客</title>
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
  <meta name="google" content="notranslate">

  
  
  <meta name="description" content="Fragment 常见问题以及androidx下Fra..."> 
  
  <meta name="author" content="杨云召（Flywith24）"> 

  
    <link rel="icon" href="/images/icons/favicon-16x16.png" type="image/png" sizes="16x16">
  
  
    <link rel="icon" href="/images/icons/favicon-32x32.png" type="image/png" sizes="32x32">
  
  
    <link rel="apple-touch-icon" href="/images/icons/apple-touch-icon.png" sizes="180x180">
  
  
    <meta rel="mask-icon" href="/images/icons/stun-logo.svg" color="#333333">
  
  
    <meta rel="msapplication-TileImage" content="/images/icons/favicon-144x144.png">
    <meta rel="msapplication-TileColor" content="#000000">
  

  <link rel="stylesheet" href="/css/style.css">

  
  <link rel="stylesheet" href="//at.alicdn.com/t/font_1445822_hhodbqn7tit.css">
  

  
  
  <link rel="stylesheet" href="https://cdn.bootcss.com/fancybox/3.5.7/jquery.fancybox.min.css">
  

  
  
  <link rel="stylesheet" href="https://cdn.bootcss.com/highlight.js/9.18.1/styles/xcode.min.css">
  

  <script>
    var CONFIG = window.CONFIG || {};
    var ZHAOO = window.ZHAOO || {};
    CONFIG = {
      isHome: false,
      fancybox: true,
      pjax: false,
      lazyload: {
        enable: true,
        loadingImage: '/images/theme/loading.gif',
      },
      donate: {
        enable: true,
        alipay: 'https://gitee.com/flywith24/Album/raw/master/img/20201015113301.jpg',
        wechat: 'https://gitee.com/flywith24/Album/raw/master/img/20201015112814.png'
      },
      motto: {
        api: '',
        default: '不人云亦云，只求接近真相.'
      },
      galleries: {
        enable: true
      },
      fab: {
        enable: true,
        alwaysShow: false
      },
      carrier: {
        enable: true
      },
      daovoice: {
        enable: true
      }
    }
  </script>

  

  
</head></html>
<body class="lock-screen">
  <div class="loading"></div>
  


<nav class="navbar">
  <div class="left"></div>
  <div class="center">你真的会用Fragment吗？Fragment常见问题以及androidx下Fragment的使用新姿势</div>
  <div class="right">
    <i class="iconfont iconmenu j-navbar-menu"></i>
  </div>
</nav>

  <nav class="menu">
  <div class="menu-wrap">
    <div class="menu-close">
      <i class="iconfont iconbaseline-close-px"></i>
    </div>
    <ul class="menu-content">
      
      
      
      
      <li class="menu-item"><a href="/ " class="underline"> 首页</a></li>
      
      
      
      
      <li class="menu-item"><a href="/archives " class="underline"> 归档</a></li>
      
      
      
      
      <li class="menu-item"><a href="/tags " class="underline"> 标签</a></li>
      
      
      
      
      <li class="menu-item"><a href="/categories " class="underline"> 分类</a></li>
      
      
      
      
      <li class="menu-item"><a href="/about " class="underline"> 关于</a></li>
      
    </ul>
    <div class="menu-copyright"><p>Copyright© 2017 - 2020 ❤️ Flywith24</p></div>
  </div>
</nav>
  <main id="main">
  <div class="container" id="container">
    <article class="article">
  <div class="wrap">
    <section class="head">
  <img   class="lazyload" data-original="https://gitee.com/flywith24/Album/raw/master/img/20201015094256.png" src=""  draggable="false">
  <div class="head-mask">
    <h1 class="head-title">你真的会用Fragment吗？Fragment常见问题以及androidx下Fragment的使用新姿势</h1>
    <div class="head-info">
      <span class="post-info-item"><i class="iconfont iconcalendar"></i>三月 02, 2020</span
        class="post-info-item">
      
      <span class="post-info-item"><i class="iconfont iconfont-size"></i>15898</span>
    </div>
  </div>
</section>
    <section class="main">
      <section class="content">
        <blockquote>
<p>在 <code>Android Jetpack</code> 组件中，<code>fragment</code>作为视图控制器之一占有很重要的位置。但由于其bug众多，暗坑无数，以至于 Square 有这样一篇博客：<a href="https://developer.squareup.com/blog/advocating-against-android-fragments/" target="_blank" rel="noopener">Advocating Against Android Fragments</a>。github上的 <a href="https://github.com/YoKeyword/Fragmentation" target="_blank" rel="noopener">Fragmentation</a> 有着 9.4k 的star。</p>
<p>而现在，<code>androidx fragment</code> 稳定版已来到 1.2.2，让我们总结一下<code>fragment</code>有哪些常见问题以及有哪些使用<code>fragment</code>的新姿势</p>
</blockquote>
<h2 id="Fragment-常见的问题"><a href="#Fragment-常见的问题" class="headerlink" title="Fragment 常见的问题"></a>Fragment 常见的问题</h2><ul>
<li><p>getSupportFragmentManager ， getParentFragmentManager 和 getChildFragmentManager</p>
</li>
<li><p>FragmentStateAdapter 和 FragmentPagerAdapter</p>
</li>
<li><p>add 和 replace </p>
</li>
<li><p>observe LiveData时传入 this 还是 viewLifecycleOwner</p>
</li>
<li><p>使用 simpleName 作为 fragment 的 tag 有何风险？</p>
</li>
<li><p>在 BottomBarNavigation 和 drawer 中如何使用Fragment多次添加？</p>
</li>
<li><p>返回栈</p>
</li>
</ul>
<h3 id="getSupportFragmentManager-getParentFragmentManager和getChildFragmentManager"><a href="#getSupportFragmentManager-getParentFragmentManager和getChildFragmentManager" class="headerlink" title="getSupportFragmentManager , getParentFragmentManager和getChildFragmentManager"></a>getSupportFragmentManager , getParentFragmentManager和getChildFragmentManager</h3><blockquote>
<p><code>FragmentManager</code>是 <code>androidx.fragment.app</code>(已弃用的不考虑)下的抽象类，创建用于 添加，移除，替换 <code>fragment</code> 的事务（<code>transaction</code>）  </p>
</blockquote>
<p>首先要确认一件事，<code>getSupportFragmentManager()</code>是 <code>FragmentActivity</code>下的方法</p>
<p><code>getParentFragmentManager</code> 和 <code>getChildFragmentManager</code> 是 <code>androidx.fragment.app.Fragment</code> 下的方法，<strong>其中  <code>androidx.fragment 1.2.0</code> 后 <code>getFragmentManager</code> 与  <code>requireFragmentManager</code> 已弃用</strong></p>
<p>明确了这件事，接下来的就很清晰了</p>
<ul>
<li><code>getSupportFragmentManager</code>与 <code>activity</code>关联，可以将其视为 <code>activity</code> 的 <code>FragmentManager</code></li>
<li><code>getChildFragmentManager</code> 与 <code>fragment</code>关联，可以将其视为<code>fragment</code>的<code>FragmentManager</code></li>
<li><code>getParentFragmentManager</code>情况稍微复杂，正常情况返回的是该<code>fragment</code> 依附的<code>activity</code>的<code>FragmentManager</code>。如果该fragment是另一个<code>fragment</code> 的子 <code>fragment</code>，则返回的是其父<code>fragment</code>的 <code>getChildFragmentManager</code></li>
</ul>
<p>如果这么说还不明白的话，我们可以做一个实践。</p>
<p>创建一个 <code>activity</code>,一个父<code>fragment</code> ，一个子<code>fragment</code></p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs kotlin"><span class="hljs-comment">// activity</span><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyActivity</span> : <span class="hljs-type">AppCompatActivity</span></span>(R.layout.activity_main) &#123;<br>    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onCreate</span><span class="hljs-params">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> &#123;<br>        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)<br>        supportFragmentManager.commit &#123;<br>            add&lt;ParentFragment&gt;(R.id.content)<br>        &#125;<br>        Log.i(<span class="hljs-string">"MyActivity"</span>, <span class="hljs-string">"supportFragmentManager <span class="hljs-variable">$supportFragmentManager</span>"</span>)<br>    &#125;<br>&#125;<br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ParentFragment</span> : <span class="hljs-type">Fragment</span></span>(R.layout.fragment_parent) &#123;<br>    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onViewCreated</span><span class="hljs-params">(view: <span class="hljs-type">View</span>, savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> &#123;<br>        <span class="hljs-keyword">super</span>.onViewCreated(view, savedInstanceState)<br>        childFragmentManager.commit &#123;<br>            add&lt;ChildFragment&gt;(R.id.content)<br>        &#125;<br>        Log.i(<span class="hljs-string">"ParentFragment"</span>, <span class="hljs-string">"parentFragmentManager <span class="hljs-variable">$parentFragmentManager</span>"</span>)<br>        Log.i(<span class="hljs-string">"ParentFragment"</span>, <span class="hljs-string">"childFragmentManager <span class="hljs-variable">$childFragmentManager</span>"</span>)<br>    &#125;<br>&#125;<br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ChildFragment</span> : <span class="hljs-type">Fragment</span></span>(R.layout.fragment_child) &#123;<br>    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onViewCreated</span><span class="hljs-params">(view: <span class="hljs-type">View</span>, savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> &#123;<br>        <span class="hljs-keyword">super</span>.onViewCreated(view, savedInstanceState)<br>        Log.i(<span class="hljs-string">"ChildFragment"</span>, <span class="hljs-string">"parentFragmentManager <span class="hljs-variable">$parentFragmentManager</span>"</span>)<br>        Log.i(<span class="hljs-string">"ChildFragment"</span>, <span class="hljs-string">"childFragmentManager <span class="hljs-variable">$childFragmentManager</span>"</span>)<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs undefined">//log<br>I/MyActivity: supportFragmentManager FragmentManager&#123;825dcef in HostCallbacks&#123;14a13fc&#125;&#125;&#125;<br>I/ParentFragment: parentFragmentManager FragmentManager&#123;825dcef in HostCallbacks&#123;14a13fc&#125;&#125;&#125;<br>I/ParentFragment: childFragmentManager FragmentManager&#123;df5de83 in ParentFragment&#123;7cdd800&#125;&#125;&#125;<br>I/ChildFragment: parentFragmentManager FragmentManager&#123;df5de83 in ParentFragment&#123;7cdd800&#125;&#125;&#125;<br>I/ChildFragment: childFragmentManager FragmentManager&#123;aba9afb in ChildFragment&#123;5cea718&#125;&#125;&#125;<br></code></pre></td></tr></table></figure>

<p>因此</p>
<ul>
<li><p>在 <code>activity</code> 中使用 <code>ViewPager</code>，<code>BottomSheetFragment</code> 和<code>DialogFragment</code> 时，都应使用 <code>getSupportFragmentManager</code></p>
</li>
<li><p>在<code>fragment</code> 中使用 <code>ViewPager</code> 时应该使用<code>getChildFragmentManager</code></p>
</li>
</ul>
<p>错误的在 <code>fragment</code> 中使用 <code>activity</code> 的 <code>FragmentManager</code> 会引发内存泄露。 为什么呢？假如您的fragment中有一些依靠 <code>ViewPager</code> 管理的子 <code>fragment</code>，并且所有这些 <code>fragment</code>  都在 <code>activity</code> 中，因为您使用的是<code>activity</code> 的<code>FragmentManager</code> 。 现在，如果关闭您的父<code>fragment</code>，它将被关闭，但不会被销毁，因为所有子<code>fragment</code>都处于活动状态，并且它们仍在内存中，从而导致泄漏。 它不仅会泄漏父<code>fragment</code>，还会泄漏所有子<code>fragment</code>，因为它们都无法从堆内存中清除。 </p>
<h3 id="FragmentStateAdapter-和-FragmentPagerAdapter"><a href="#FragmentStateAdapter-和-FragmentPagerAdapter" class="headerlink" title="FragmentStateAdapter 和 FragmentPagerAdapter"></a>FragmentStateAdapter 和 FragmentPagerAdapter</h3><p><code>FragmentPagerAdapter</code>将整个 <code>fragment</code>存储在内存中，如果<code>ViewPager</code>中使用了大量  <code>fragment</code>，则可能导致内存开销增加。 <code>FragmentStatePagerAdapter</code>仅存储片段的<code>savedInstanceState</code>，并在失去焦点时销毁所有  <code>fragment</code>。</p>
<p>让我们看看常见的两个问题</p>
<h4 id="1-刷新ViewPager不生效"><a href="#1-刷新ViewPager不生效" class="headerlink" title="1. 刷新ViewPager不生效"></a>1. 刷新ViewPager不生效</h4><p><code>ViewPager</code> 中的 <code>fragment</code> 是通过 <code>activity</code>或 <code>fragment</code>的 <code>FragmentManager</code> 管理的，<code>FragmentManager</code> 包含了<code>viewpager</code>的所有<code>fragment</code>的实例</p>
<p>因此，当<code>ViewPager</code>没有刷新时，它只是<code>FragmentManager</code>仍保留的旧 <code>fragment</code> 实例。 您需要找出为什么<code>FragmentManger</code>持有<code>fragment</code>实例的原因。</p>
<h4 id="2-在Viewpager中访问当前fragment"><a href="#2-在Viewpager中访问当前fragment" class="headerlink" title="2. 在Viewpager中访问当前fragment"></a>2. 在Viewpager中访问当前fragment</h4><p>这也是我们遇到的一个非常普遍的问题。 如果遇到这种情况，我们一般在 <code>adapter</code> 内部创建 <code>fragment</code> 的数组列表，或者尝试使用某些标签访问<code>fragment</code>。 不过还有另一种选择。 <code>FragmentStateAdapter</code> 和<code>FragmentPagerAdapter</code>都提供方法<code>setPrimaryItem</code>。 可以用来设置当前<code>fragment</code>，如下所示：</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs kotlin"> <span class="hljs-keyword">var</span> fragment: ChildFragment? = <span class="hljs-literal">null</span><br> <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">setPrimaryItem</span><span class="hljs-params">(container: <span class="hljs-type">ViewGroup</span>, position: <span class="hljs-type">Int</span>, any: <span class="hljs-type">Any</span>)</span></span> &#123;<br>   <span class="hljs-keyword">if</span> (getChildFragment() != any)<br>   	fragment = any <span class="hljs-keyword">as</span> ChildFragment<br>   <span class="hljs-keyword">super</span>.setPrimaryItem(container, position, any)<br>  &#125;<br>  <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getChildFragment</span><span class="hljs-params">()</span></span>: ChildFragment? = fragment<br><br><span class="hljs-comment">//use</span><br>mAapter.getChildFragment()<br></code></pre></td></tr></table></figure>

<h3 id="add-和-replace-如何选择？"><a href="#add-和-replace-如何选择？" class="headerlink" title="add 和 replace 如何选择？"></a>add 和 replace 如何选择？</h3><p>在我们的<code>activity</code>中，我们有一个容器，其中装有<code>fragment</code>。</p>
<p><code>add</code>只会将一个<code>fragment</code>添加到容器中。 假设您将<code>FragmentA</code>和<code>FragmentB</code>添加到容器中。 容器将具有<code>FragmentA</code>和<code>FragmentB</code>，如果容器是<code>FrameLayout</code>，则将<code>fragment</code>一个添加在另一个之上。</p>
<p><code>replace</code>将简单地替换容器顶部的一个<code>fragment</code>，因此，如果我创建了 <code>FragmentC</code>并 <code>replace</code> 顶部的 <code>FragmentB</code>，则<code>FragmentB</code>将被从容器中删除（执行<code>onDestroy</code>，除非您调用<code>addToBackStack</code>，仅执行<code>onDestroyView</code>），而<code>FragmentC</code>将位于顶部。</p>
<p>那么如何选择呢？ <code>replace</code>删除现有<code>fragment</code>并添加一个新<code>fragment</code>。 这意味着当您按下返回按钮时，将创建被替换的<code>fragment</code>，并调用其<code>onCreateView</code>。 另一方面，<code>add</code>保留现有<code>fragment</code>，并添加一个新<code>fragment</code>，这意味着现有<code>fragment</code>将处于活动状态，并且它们不会处于 “paused” 状态。 因此，按下返回按钮时，现有<code>fragment</code>（添加新<code>fragment</code>之前的<code>fragment</code>）不会调用<code>onCreateView</code>。 就<code>fragment</code>的生命周期事件而言，在<code>replace</code>的情况下将调用<code>onPause</code>，<code>onResume</code>，<code>onCreateView</code>和其他生命周期事件，在<code>add</code>的情况下则不会。</p>
<p>如果不需要重新访问当前<code>fragment</code>并且不再需要当前<code>fragment</code>，请使用<code>replace</code>。 另外，如果您的应用有内存限制，请考虑使用<code>replace</code>。</p>
<h3 id="observe-LiveData时传入-this-还是-viewLifecycleOwner"><a href="#observe-LiveData时传入-this-还是-viewLifecycleOwner" class="headerlink" title="observe LiveData时传入 this 还是 viewLifecycleOwner"></a>observe LiveData时传入 this 还是 viewLifecycleOwner</h3><p><code>androidx fragment 1.2.0</code> 起，添加了新的 Lint 检查，以确保您在从 <code>onCreateView()</code>、<code>onViewCreated()</code> 或 <code>onActivityCreated()</code> 观察 <code>LiveData</code> 时使用 <code>getViewLifecycleOwner()</code></p>
<h3 id="使用-simpleName-作为-fragment-的-tag-有何风险？"><a href="#使用-simpleName-作为-fragment-的-tag-有何风险？" class="headerlink" title="使用 simpleName 作为 fragment 的 tag 有何风险？"></a>使用 simpleName 作为 fragment 的 tag 有何风险？</h3><p>一般情况下我们会使用calss的<code>simpleName</code> 作为<code>fragment</code> 的tag</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs kotlin">supportFragmentManager.commit &#123;<br>	replace(R.id.content,MyFragment.newInstance(<span class="hljs-string">"Fragment"</span>),<br>            MyFragment::<span class="hljs-class"><span class="hljs-keyword">class</span>.<span class="hljs-title">java</span>.<span class="hljs-title">simpleName</span>)</span><br>    addToBackStack(<span class="hljs-literal">null</span>)<br>&#125;<br></code></pre></td></tr></table></figure>

<p>这样做不会出现什么问题，但是…</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs kotlin"><span class="hljs-keyword">val</span> fragment = supportFragmentManager.findFragmentByTag(tag)<br></code></pre></td></tr></table></figure>

<p>这样获取到的fragment可能不是想要的结果。</p>
<p>为什么呢？</p>
<p>加入有两个 fragment，经过混淆，它们变成</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs undefined">com.mypackage.FragmentA → com.mypackage.c.a<br>com.mypackage.FragmentB → com.mypackage.c.a.a<br></code></pre></td></tr></table></figure>

<p>上面是混淆了 full name，如果是simpleName 呢？</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs undefined">com.mypackage.FragmentA → a<br>com.mypackage.FragmentB → a<br></code></pre></td></tr></table></figure>

<p>WTF！</p>
<p><strong>所以在设置tag时尽量用全名或者常量</strong></p>
<h3 id="在-BottomBarNavigation-和-drawer-中如何使用Fragment多次添加？"><a href="#在-BottomBarNavigation-和-drawer-中如何使用Fragment多次添加？" class="headerlink" title="在 BottomBarNavigation 和 drawer 中如何使用Fragment多次添加？"></a>在 BottomBarNavigation 和 drawer 中如何使用Fragment多次添加？</h3><p>当我们使用<code>BottomBarNavigation</code>和 <code>NavigationDrawer</code>时，通常会看到诸如<code>fragment</code> 重建或多次添加相同<code>fragment</code>之类的问题。</p>
<p>在这种情况下，您可以使用<code>show / hide</code> 而不是 <code>add</code> 或 <code>replace</code>。</p>
<h3 id="返回栈"><a href="#返回栈" class="headerlink" title="返回栈"></a>返回栈</h3><p>如果您想在<code>fragment</code>的一系列跳转中按返回键返回上一个<code>fragment</code>，应该在<code>commit</code> <code>transaction</code>之前调用<code>addToBackStack</code>方法</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs kotlin"><span class="hljs-comment">//使用该扩展 androidx.fragment:fragment-ktx:1.2.0 以上</span><br>parentFragmentManager.commit &#123;<br>	addToBackStack(<span class="hljs-literal">null</span>)<br>  	add&lt;SecondFragment&gt;(R.id.content)<br>&#125;<br></code></pre></td></tr></table></figure>

<h2 id="Fragment的使用新姿势"><a href="#Fragment的使用新姿势" class="headerlink" title="Fragment的使用新姿势"></a>Fragment的使用新姿势</h2><ul>
<li><p>fragment-ktx 有哪些好用的扩展函数</p>
</li>
<li><p>fragment 之间和与 activity 通信</p>
</li>
<li><p>使用 FragmentContainerView 作为 fragment 容器</p>
</li>
<li><p>FragmentFactory 的使用</p>
</li>
<li><p>Fragment 返回键拦截</p>
</li>
<li><p>Fragment 使用 ViewBinding</p>
</li>
<li><p>Fragment 使用 ViewPager2</p>
</li>
<li><p>不需要重写 onCreateView 了？</p>
</li>
<li><p>使用require_()方法</p>
</li>
</ul>
<h3 id="fragment-ktx-有哪些好用的扩展函数"><a href="#fragment-ktx-有哪些好用的扩展函数" class="headerlink" title="fragment-ktx 有哪些好用的扩展函数"></a>fragment-ktx 有哪些好用的扩展函数</h3><h4 id="1-FragmentManagerKt"><a href="#1-FragmentManagerKt" class="headerlink" title="1. FragmentManagerKt"></a>1. FragmentManagerKt</h4><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs kotlin"><span class="hljs-comment">//before</span><br>supportFragmentManager<br>    .beginTransaction()<br>    .add(R.id.content,Fragment1())<br>    .commit()<br><br><span class="hljs-comment">//after</span><br>supportFragmentManager.commit &#123;<br>	add&lt;Fragment1&gt;(R.id.content)<br>&#125;<br></code></pre></td></tr></table></figure>

<h4 id="2-FragmentViewModelLazyKt"><a href="#2-FragmentViewModelLazyKt" class="headerlink" title="2. FragmentViewModelLazyKt"></a>2. FragmentViewModelLazyKt</h4><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs kotlin"><span class="hljs-comment">//before</span><br><span class="hljs-comment">//共享范围activity</span><br><span class="hljs-keyword">val</span> mViewMode1l = ViewModelProvider(requireActivity()).<span class="hljs-keyword">get</span>(UpdateAppViewModel::<span class="hljs-class"><span class="hljs-keyword">class</span>.<span class="hljs-title">java</span>)</span><br><span class="hljs-comment">//共享范围fragment 内部</span><br><span class="hljs-keyword">val</span> mViewMode1l = ViewModelProvider(<span class="hljs-keyword">this</span>).<span class="hljs-keyword">get</span>(UpdateAppViewModel::<span class="hljs-class"><span class="hljs-keyword">class</span>.<span class="hljs-title">java</span>)</span><br><br><span class="hljs-comment">//after</span><br><span class="hljs-comment">//共享范围activity</span><br><span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> mViewModel <span class="hljs-keyword">by</span> activityViewModels&lt;MyViewModel&gt;()<br><span class="hljs-comment">//共享范围fragment 内部</span><br><span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> mViewModel <span class="hljs-keyword">by</span> viewModel&lt;MyViewModel&gt;()<br></code></pre></td></tr></table></figure>

<blockquote>
<p><strong>注意：ViewModelProviders.of(this).get(MyViewModel.class); 的方式已弃用</strong> </p>
<p><strong><code>lifecycle-extensions</code> 依赖包已弃用</strong></p>
</blockquote>
<h3 id="fragment-之间和与-activity-通信"><a href="#fragment-之间和与-activity-通信" class="headerlink" title="fragment 之间和与 activity 通信"></a>fragment 之间和与 activity 通信</h3><p>fragment 和 fragment之间，fragment 和 activity 之间的通信有很多方法，android jetpack 推荐我们使用 ViewModel + LiveData 处理</p>
<p>同一个activity 内的 fragment 之间通信，可以使用作用范围为activity的ViewModel，activity与 fragment通信同理。详情可移步 <a href="https://developer.android.com/jetpack/docs/guide" target="_blank" rel="noopener">Android官方应用架构指南</a></p>
<h3 id="使用-FragmentContainerView-作为-fragment-容器"><a href="#使用-FragmentContainerView-作为-fragment-容器" class="headerlink" title="使用 FragmentContainerView 作为 fragment 容器"></a>使用 FragmentContainerView 作为 fragment 容器</h3><p>过去我们使用 <code>FrameLayout</code> 作为 <code>Fragment</code> 的容器，在 <code>AndroidX Fragment 1.2.0</code> 后，可以使用 <code>FragmentContainerView</code> 代替 <code>Fragment</code> 。</p>
<p>它修复了一些动画 z轴索引顺序问题和窗口插入调度，这意味着两个<code>fragment</code>之间的退出和进入过渡不会互相重叠。使用<code>FragmentContainerView</code>将先开启退出动画然后才是进入动画。</p>
<p><code>FragmentContainerView</code>  是专门为 fragment设计的自定义View，它继承自 FrameLayout</p>
<p><code>android:name</code> 属性允许您添加<code>fragment</code>，<code>android:tag</code> 属性可以为<code>fragment</code>设置tag</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">androidx.fragment.app.FragmentContainerView</span><br>       <span class="hljs-attr">xmlns:android</span>=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span><br>       <span class="hljs-attr">xmlns:app</span>=<span class="hljs-string">"http://schemas.android.com/apk/res-auto"</span><br>       <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/fragment_container_view"</span><br>       <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span><br>       <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"match_parent"</span><br>       <span class="hljs-attr">android:name</span>=<span class="hljs-string">"com.example.MyFragment"</span><br>       <span class="hljs-attr">android:tag</span>=<span class="hljs-string">"my_tag"</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">androidx.fragment.app.FragmentContainerView</span>&gt;</span><br></code></pre></td></tr></table></figure>

<h3 id="FragmentFactory-的使用"><a href="#FragmentFactory-的使用" class="headerlink" title="FragmentFactory 的使用"></a>FragmentFactory 的使用</h3><p>过去，我们只能使用其默认的空构造函数实例化Fragment实例。 这是因为在某些情况下，例如配置更改和应用程序的流程重新创建，系统需要重新初始化。 如果不是默认的构造方法，系统将不知道如何重新初始化Fragment实例。</p>
<p>创建FragmentFactory来解决此限制。 通过向其提供实例化Fragment所需的必要参数/依赖关系，它可以帮助系统创建Fragment实例。</p>
<p>过去我们实例化fragment并传递参数会使用类似下面的代码</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyFragment</span> : <span class="hljs-type">Fragment</span></span>() &#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> arg: String<br>    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onCreate</span><span class="hljs-params">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> &#123;<br>        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)<br>        arguments?.getString(ARG) ?: <span class="hljs-string">""</span><br>    &#125;<br>    <span class="hljs-keyword">companion</span> <span class="hljs-keyword">object</span> &#123;<br>        <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">newInstance</span><span class="hljs-params">(arg: <span class="hljs-type">String</span>)</span></span> =<br>            MyFragment().apply &#123;<br>                arguments = Bundle().apply &#123;<br>                    putString(ARG, arg)<br>                &#125;<br>            &#125;<br>    &#125;<br>&#125;<br><br><span class="hljs-comment">//use</span><br><span class="hljs-keyword">val</span> fragment = MyFragment.newInstance(<span class="hljs-string">"my argument"</span>)<br></code></pre></td></tr></table></figure>

<p>如果您的Fragment有一个非空的构造函数，则需要创建一个FragmentFactory来处理它的初始化。</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyFragmentFactory</span></span>(<span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> arg: String) : FragmentFactory() &#123;<br>    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">instantiate</span><span class="hljs-params">(classLoader: <span class="hljs-type">ClassLoader</span>, className: <span class="hljs-type">String</span>)</span></span>: Fragment &#123;<br>        <span class="hljs-keyword">if</span> (className == MyFragment::<span class="hljs-class"><span class="hljs-keyword">class</span>.<span class="hljs-title">java</span>.<span class="hljs-title">name</span>) </span>&#123;<br>            <span class="hljs-keyword">return</span> MyFragment(arg)<br>        &#125;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">super</span>.instantiate(classLoader, className)<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><code>fragment</code>由<code>FragmentManager</code> 管理，因此很自然，<code>FragmentFactory</code>需要添加到<code>FragmentManager</code>才能使用。</p>
<p>那么什么时候把<code>FragmentFactory</code> 添加到<code>FragmentManager</code>呢？</p>
<p><strong>父类调用 <code>Activity#onCreate()</code>  和 <code>Fragment#onCreate()</code>之前</strong></p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HostActivity</span> : <span class="hljs-type">AppCompatActivity</span></span>() &#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> customFragmentFactory = CustomFragmentFactory(Dependency())<br><br>    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onCreate</span><span class="hljs-params">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> &#123;<br>        supportFragmentManager.fragmentFactory = customFragmentFactory<br>        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)<br>        <span class="hljs-comment">// ...</span><br>    &#125;<br>&#125;<br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ParentFragment</span> : <span class="hljs-type">Fragment</span></span>() &#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> customFragmentFactory = CustomFragmentFactory(Dependency())<br><br>    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onCreate</span><span class="hljs-params">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> &#123;<br>        childFragmentManager.fragmentFactory = customFragmentFactory<br>        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)<br>        <span class="hljs-comment">// ...</span><br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>如果您的<code>Fragment</code>具有默认的空构造函数，则无需使用<code>FragmentFactory</code>。 但是，如果您的<code>Fragment</code>在其构造函数中接受参数，则必须使用<code>FragmentFactory</code>，否则将抛出<code>Fragment.InstantiationException</code>，因为将使用的默认<code>FragmentFactory</code>将不知道如何实例化<code>Fragment</code>的实例。</p>
<h3 id="Fragment-返回键拦截"><a href="#Fragment-返回键拦截" class="headerlink" title="Fragment 返回键拦截"></a>Fragment 返回键拦截</h3><p>有时候，您需要阻止用户返回上一级。 在这种情况下，您需要在 <code>Activity</code> 中重写 <code>onBackPressed()</code> 方法。 但是，当您使用 <code>Fragment</code> 时，没有直接的方法来拦截返回。 在 <code>Fragment</code> 类中没有可用的 <code>onBackPressed()</code> 方法，这是为了防止同时存在多个 <code>Fragment</code> 时发生意外行为。</p>
<p>但是，从 <code>AndroidX</code> <code>Activity 1.0.0</code> 开始，您可以使用 <code>OnBackPressedDispatcher</code> 在您可以访问该 <code>Activity</code> 的代码的任何位置（例如，在 <code>Fragment</code> 中）注册 <code>OnBackPressedCallback</code>。</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyFragment</span> : <span class="hljs-type">Fragment</span></span>() &#123;<br>  <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onAttach</span><span class="hljs-params">(context: <span class="hljs-type">Context</span>)</span></span> &#123;<br>    <span class="hljs-keyword">super</span>.onAttach(context)<br>    <span class="hljs-keyword">val</span> callback = <span class="hljs-keyword">object</span> : OnBackPressedCallback(<span class="hljs-literal">true</span>) &#123;<br>      <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">handleOnBackPressed</span><span class="hljs-params">()</span></span> &#123;<br>        <span class="hljs-comment">// Do something</span><br>      &#125;<br>    &#125;<br>    requireActivity().onBackPressedDispatcher.addCallback(<span class="hljs-keyword">this</span>, callback)<br>  &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="Fragment-使用-ViewBinding"><a href="#Fragment-使用-ViewBinding" class="headerlink" title="Fragment 使用 ViewBinding"></a>Fragment 使用 ViewBinding</h3><p><code>Android Studio 3.6.0</code> 后提供了 <code>ViewBindind</code>的支持，完整使用流程参见 <a href="https://juejin.im/post/5e4806f3e51d4526c550a2ef" target="_blank" rel="noopener">[译]深入研究ViewBinding 在 include, merge, adapter, fragment, activity 中使用</a></p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HomeFragment</span> : <span class="hljs-type">Fragment</span></span>() &#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> _binding: FragmentHomeBinding? = <span class="hljs-literal">null</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> binding <span class="hljs-keyword">get</span>() = _binding!!<br><br>    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onCreateView</span><span class="hljs-params">(inflater: <span class="hljs-type">LayoutInflater</span>, container: <span class="hljs-type">ViewGroup</span>?, savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span>: View? &#123;<br>        _binding = FragmentHomeBinding.inflate(inflater, container, <span class="hljs-literal">false</span>)<br>        <span class="hljs-keyword">return</span> binding.root<br>    &#125;<br>    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onDestroyView</span><span class="hljs-params">()</span></span> &#123;<br>        _binding = <span class="hljs-literal">null</span><br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="Fragment-使用-ViewPager2"><a href="#Fragment-使用-ViewPager2" class="headerlink" title="Fragment 使用 ViewPager2"></a>Fragment 使用 ViewPager2</h3><p><code>ViewPager</code>使用了三个<code>adapter</code>的抽象类，而<code>ViewPager2</code>中只有两个</p>
<ul>
<li>ViewPager 中使用 <code>PagerAdaper</code>，ViewPager2 中使用 <strong><code>Recyclerview.Adapter</code></strong></li>
<li>ViewPager 中使用 <code>FragmentPagerAdapter</code> ，ViewPager2中使用 <strong><code>FragmentStateAdapter</code></strong></li>
<li>ViewPager 中使用 <code>FragmentStatePagerAdapter</code> ，ViewPager2中使用 <strong><code>FragmentStateAdapter</code></strong></li>
</ul>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs kotlin"><span class="hljs-comment">// A simple ViewPager adapter class for paging through fragments</span><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ScreenSlidePagerAdapter</span></span>(fm: FragmentManager) : FragmentStatePagerAdapter(fm) &#123;<br>    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getCount</span><span class="hljs-params">()</span></span>: <span class="hljs-built_in">Int</span> = NUM_PAGES<br><br>    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getItem</span><span class="hljs-params">(position: <span class="hljs-type">Int</span>)</span></span>: Fragment = ScreenSlidePageFragment()<br>&#125;<br><br><span class="hljs-comment">// An equivalent ViewPager2 adapter class</span><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ScreenSlidePagerAdapter</span></span>(fa: FragmentActivity) : FragmentStateAdapter(fa) &#123;<br>    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getItemCount</span><span class="hljs-params">()</span></span>: <span class="hljs-built_in">Int</span> = NUM_PAGES<br><br>    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createFragment</span><span class="hljs-params">(position: <span class="hljs-type">Int</span>)</span></span>: Fragment = ScreenSlidePageFragment()<br>&#125;<br></code></pre></td></tr></table></figure>

<p>使用 <code>TabLayout</code>的变化，<code>TabLayout</code> 已从<code>ViewPager2</code>中解耦，如果使用<code>TabLayout</code>，需要引入依赖</p>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs groovy">implementation <span class="hljs-string">"com.google.android.material:material:1.1.0"</span><br></code></pre></td></tr></table></figure>

<p>对于<code>ViewPager2</code> ，<code>TabLayout</code>布局应与<code>ViewPager2</code>在同一级别</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- A ViewPager element with a TabLayout --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">androidx.viewpager.widget.ViewPager</span><br>    <span class="hljs-attr">xmlns:android</span>=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span><br>    <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/pager"</span><br>    <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span><br>    <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"match_parent"</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">com.google.android.material.tabs.TabLayout</span><br>        <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/tab_layout"</span><br>        <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span><br>        <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"wrap_content"</span> /&gt;</span><br><br><span class="hljs-tag">&lt;/<span class="hljs-name">androidx.viewpager.widget.ViewPager</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- A ViewPager2 element with a TabLayout --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">LinearLayout</span> <span class="hljs-attr">xmlns:android</span>=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span><br>    <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span><br>    <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"match_parent"</span><br>    <span class="hljs-attr">android:orientation</span>=<span class="hljs-string">"vertical"</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">com.google.android.material.tabs.TabLayout</span><br>        <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/tab_layout"</span><br>        <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span><br>        <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"wrap_content"</span> /&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">androidx.viewpager2.widget.ViewPager2</span><br>        <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/pager"</span><br>        <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span><br>        <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"0dp"</span><br>        <span class="hljs-attr">android:layout_weight</span>=<span class="hljs-string">"1"</span> /&gt;</span><br><br><span class="hljs-tag">&lt;/<span class="hljs-name">LinearLayout</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>使用<code>ViewPager</code>时，<code>TabLayout</code>与<code>ViewPager</code>联动需要调用 <code>setupWithViewPager</code>，并重写<code>getPageTitle</code>方法，而<code>ViewPager2</code>改为使用<code>TabLayoutMediator</code>对象</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><code class="hljs kotlin"><span class="hljs-comment">// Integrating TabLayout with ViewPager</span><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CollectionDemoFragment</span> : <span class="hljs-type">Fragment</span></span>() &#123;<br>    ...<br>    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onViewCreated</span><span class="hljs-params">(view: <span class="hljs-type">View</span>, savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> &#123;<br>        <span class="hljs-keyword">val</span> tabLayout = view.findViewById(R.id.tab_layout)<br>        tabLayout.setupWithViewPager(viewPager)<br>    &#125;<br>    ...<br>&#125;<br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DemoCollectionPagerAdapter</span></span>(fm: FragmentManager) : FragmentStatePagerAdapter(fm) &#123;<br><br>    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getCount</span><span class="hljs-params">()</span></span>: <span class="hljs-built_in">Int</span>  = <span class="hljs-number">4</span><br><br>    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getPageTitle</span><span class="hljs-params">(position: <span class="hljs-type">Int</span>)</span></span>: CharSequence &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">"OBJECT <span class="hljs-subst">$&#123;(position + <span class="hljs-number">1</span>)&#125;</span>"</span><br>    &#125;<br>    ...<br>&#125;<br><br><span class="hljs-comment">// Integrating TabLayout with ViewPager2</span><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CollectionDemoFragment</span> : <span class="hljs-type">Fragment</span></span>() &#123;<br>    ...<br>    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onViewCreated</span><span class="hljs-params">(view: <span class="hljs-type">View</span>, savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> &#123;<br>        <span class="hljs-keyword">val</span> tabLayout = view.findViewById(R.id.tab_layout)<br>        TabLayoutMediator(tabLayout, viewPager) &#123; tab, position -&gt;<br>            tab.text = <span class="hljs-string">"OBJECT <span class="hljs-subst">$&#123;(position + <span class="hljs-number">1</span>)&#125;</span>"</span><br>        &#125;.attach()<br>    &#125;<br>    ...<br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="不需要重写-onCreateView-了？"><a href="#不需要重写-onCreateView-了？" class="headerlink" title="不需要重写 onCreateView 了？"></a>不需要重写 onCreateView 了？</h3><p><code>androidx fragment 1.1.0</code> 后，您可以使用将 <code>layoutId</code> 作为参数的构造函数，这样就无需重写 <code>onCreateView</code> 方法了</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyActivity</span> : <span class="hljs-type">AppCompatActivity</span></span>(R.layout.my_activity)<br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyFragmentActivity</span>: <span class="hljs-type">FragmentActivity</span></span>(R.layout.my_fragment_activity)<br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyFragment</span> : <span class="hljs-type">Fragment</span></span>(R.layout.my_fragment)<br></code></pre></td></tr></table></figure>

<h3 id="使用require-方法"><a href="#使用require-方法" class="headerlink" title="使用require_()方法"></a>使用require_()方法</h3><p><code>androidx fragment 1.2.2</code> 起，新增了一项lint检查，<code>fragment</code> 建议使用关联的<code>require_()</code>方法获取更多描述性错误消息，而不是使用<code>checkNotNull(get_())</code>，<code>requireNonNull(get_())</code> 或<code>get()！</code> 适用于所有包含 get 和 require Fragment API</p>
<p>例如：使用 <code>requireActivity()</code> 替代 <code>getActivity()</code></p>
      </section>
      <section class="extra">
        
        <ul class="copyright">
  
  <li><strong>本文作者：</strong>杨云召（Flywith24）</li>
  <li><strong>本文链接：</strong><a href="https://flywith24.gitee.io/2020/03/02/Jetpack-fragment/index.html">https://flywith24.gitee.io/2020/03/02/Jetpack-fragment/index.html</a></li>
  <li><strong>版权声明：</strong>本博客所有文章均采用<a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh"
      rel="external nofollow" target="_blank"> BY-NC-SA </a>许可协议，转载请注明出处！</li>
  
</ul>
        
        
        <section class="donate">
  <div class="qrcode">
    <img   class="lazyload" data-original="https://gitee.com/flywith24/Album/raw/master/img/20201015113301.jpg" src="" >
  </div>
  <div class="icon">
    <a href="javascript:;" id="alipay"><i class="iconfont iconalipay"></i></a>
    <a href="javascript:;" id="wechat"><i class="iconfont iconwechat-fill"></i></a>
  </div>
</section>
        
        
  <ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/Jetpack/">Jetpack</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/MVVM/">MVVM</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/androidx/">androidx</a></li></ul>

        
<nav class="nav">
  
    <a href="/2020/03/10/Jetpack-fragment-lifecycle/"><i class="iconfont iconleft"></i>从源码角度看Fragment的启动流程及生命周期 基于AndroidX Fragment1.2.2</a>
  
  
    <a href="/2020/03/01/Jetpack-dependencies/">Jetpack 主要依赖关系<i class="iconfont iconright"></i></a>
  
</nav>

      </section>
      
      <section class="comments">
  
  <div class="btn" id="comments-btn">查看评论</div>
  
  
<div id="valine"></div>
<script defer src="//unpkg.com/valine/dist/Valine.min.js"></script>
<script>
  window.onload = function () {
    var loadValine = function () {
      new Valine({
        el: '#valine',
        app_id: "SHA3gzCcxFlqaPcGRnX4UgET-gzGzoHsz",
        app_key: "OYo7ITS4AzTvBUvb1yIY8oaf",
        placeholder: "期待你的留言",
        avatar: "mp",
        pageSize: "10",
        lang: "zh-CN",
      });
    }
    if ( true ) {
      $("#comments-btn").on("click", function () {
        $(this).hide();
        loadValine();
      });
    } else {
      loadValine();
    }
  };
</script>

</section>
      
    </section>
  </div>
</article>
  </div>
</main>
  <footer class="footer">
  <div class="footer-social">
    
    
    
    
    
    <a href="tencent://message/?Menu=yes&uin=1032367864 " target="_blank" onMouseOver="this.style.color= '#12B7F5'"
      onMouseOut="this.style.color='#33333D'">
      <i class="iconfont footer-social-item  iconQQ "></i>
    </a>
    
    
    
    
    
    <a href="javascript:; " target="_blank" onMouseOver="this.style.color= '#8bc34a'"
      onMouseOut="this.style.color='#33333D'">
      <i class="iconfont footer-social-item  iconwechat-fill "></i>
    </a>
    
    
    
    
    
    <a href="https://flywith24.gitee.io/about/ " target="_blank" onMouseOver="this.style.color= '#d32f2f'"
      onMouseOut="this.style.color='#33333D'">
      <i class="iconfont footer-social-item  iconheart "></i>
    </a>
    
    
    
    
    
    <a href="https://github.com/Flywith24 " target="_blank" onMouseOver="this.style.color= '#24292E'"
      onMouseOut="this.style.color='#33333D'">
      <i class="iconfont footer-social-item  icongithub-fill "></i>
    </a>
    
    
    
    
    
    <a href="mailto:youngyunzhao@163.com " target="_blank" onMouseOver="this.style.color='#FFBE5B'"
      onMouseOut="this.style.color='#33333D'">
      <i class="iconfont footer-social-item  iconmail"></i>
    </a>
    
  </div>
  <div class="footer-copyright"><p>Copyright© 2017 - 2020 ❤️ Flywith24</p></div>
</footer>
  
      <div class="fab fab-plus">
    <i class="iconfont iconplus"></i>
  </div>
  
  <div class="fab fab-daovoice">
    <i class="iconfont iconcomment"></i>
  </div>
  
  <div class="fab fab-up">
    <i class="iconfont iconcaret-up"></i>
  </div>
  
<script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"pluginRootPath":"live2dw/","pluginJsPath":"lib/","pluginModelPath":"assets/","tagMode":false,"debug":false,"model":{"jsonPath":"/live2dw/assets/shizuku.model.json"},"display":{"position":"left","width":150,"height":300},"mobile":{"show":"tfalse"},"log":false});</script></body>

<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>




<script src="https://cdn.bootcdn.net/ajax/libs/jquery.lazyload/1.9.1/jquery.lazyload.min.js"></script>




<script src="https://cdn.bootcss.com/fancybox/3.5.7/jquery.fancybox.min.js"></script>




<script src="/js/utils.js"></script>
<script src="/js/modules.js"></script>
<script src="/js/zui.js"></script>
<script src="/js/script.js"></script>




<script>
  (function (i, s, o, g, r, a, m) {
    i["DaoVoiceObject"] = r;
    i[r] = i[r] || function () {
      (i[r].q = i[r].q || []).push(arguments)
    }, i[r].l = 1 * new Date();
    a = s.createElement(o), m = s.getElementsByTagName(o)[0];
    a.async = 1;
    a.src = g;
    a.charset = "utf-8";
    m.parentNode.insertBefore(a, m)
  })(window, document, "script", ('https:' == document.location.protocol ? 'https:' : 'http:') +
    "//widget.daovoice.io/widget/0f81ff2f.js", "daovoice")
  daovoice('init', {
    app_id: "7785620b"
  }, {
    launcher: {
      disableLauncherIcon: true,
    },
  });
  daovoice('update');
</script>



<script>
  (function () {
    var bp = document.createElement('script');
    var curProtocol = window.location.protocol.split(':')[0];
    if (curProtocol === 'https') {
      bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
    } else {
      bp.src = 'http://push.zhanzhang.baidu.com/push.js';
    }
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(bp, s);
  })();
</script>


<script>
  var _hmt = _hmt || [];
  (function () {
    var hm = document.createElement("script");
    hm.src = "https://hm.baidu.com/hm.js?4c204d8bc027a0455b5fc642ac334ca8";
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(hm, s);
  })();
</script>










</html>